﻿
Imports System.Text
Imports std

Public Module _escape

    Private defaultEscapeMap As map(Of Char, String) = Nothing
    Private defaultUnescapeMap As map(Of Char, String) = Nothing

    Public Function escapeEx(ByVal src As String, ByRef dst As String, _
                             Optional ByVal escapeChar As Char = character.rightSlash, _
                             Optional ByVal escapeMap As map(Of Char, String) = Nothing, _
                             Optional ByVal useDefaultEscapeMap As Boolean = True) As Boolean
        Dim rtn As StringBuilder = Nothing
        rtn = New StringBuilder(convertor.toint32(strlen(src)) << 1)

        If escapeMap Is Nothing AndAlso useDefaultEscapeMap Then
            escapeMap = defaultEscapeMap
        End If

        Dim i As Int64
        For i = 0 To strlen(src) - 1
            If src(i) = escapeChar Then
                rtn.Append(escapeChar)
                rtn.Append(escapeChar)
            ElseIf Not escapeMap Is Nothing Then
                Dim it As map(Of Char, String).iterator = Nothing
                it = escapeMap.find(src(i))
                If it <> escapeMap.end() Then
                    rtn.Append(escapeChar)
                    rtn.Append((+it).second)
                Else
                    rtn.Append(src(i))
                End If
            End If
        Next

        dst = Convert.ToString(rtn)
        Return True
    End Function

    Public Function unescapeEx(ByVal src As String, ByRef dst As String, _
                               Optional ByVal escapeChar As Char = character.rightSlash, _
                               Optional ByVal unescapeMap As map(Of Char, String) = Nothing, _
                               Optional ByVal useDefaultUnescapeMap As Boolean = True) As Boolean
        Dim rtn As StringBuilder = Nothing
        rtn = New StringBuilder(convertor.toint32(strlen(src)) << 1)

        If unescapeMap Is Nothing AndAlso useDefaultUnescapeMap Then
            unescapeMap = defaultUnescapeMap
        End If

        Dim i As Int64
        For i = 0 To strlen(src) - 1
            If src(i) = escapeChar AndAlso i + 1 < strlen(src) Then
                If src(i + 1) = escapeChar Then
                    rtn.Append(escapeChar)
                    i += 1
                ElseIf Not unescapeMap Is Nothing Then
                    Dim it As map(Of Char, String).iterator = Nothing
                    it = unescapeMap.find(src(i + 1))
                    If it <> unescapeMap.end() Then
                        rtn.Append((+it).second)
                        i += 1
                    Else
                        rtn.Append(escapeChar)
                    End If
                End If
            Else
                rtn.Append(src(i))
            End If
        Next

        dst = Convert.ToString(rtn)
        Return True
    End Function

    Public Function escapeBackEx(ByVal src As String, ByRef dst As String, _
                                 Optional ByVal escapeChar As Char = character.rightSlash, _
                                 Optional ByVal unescapeMap As map(Of Char, String) = Nothing, _
                                 Optional ByVal useDefaultUnescapeMap As Boolean = True) As Boolean
        Return unescapeEx(src, dst, escapeChar, unescapeMap, useDefaultUnescapeMap)
    End Function

    Public Function escapeEx(ByVal src As String, Optional ByVal escapeChar As Char = character.rightSlash, _
                             Optional ByVal escapeMap As map(Of Char, String) = Nothing, _
                             Optional ByVal useDefaultEscapeMap As Boolean = True) As String
        Dim rtn As String = Nothing
        If escapeEx(src, rtn, escapeChar, escapeMap, useDefaultEscapeMap) Then
            Return rtn
        Else
            Return Nothing
        End If
    End Function

    Public Function unescapeEx(ByVal src As String, Optional ByVal escapeChar As Char = character.rightSlash, _
                               Optional ByVal unescapeMap As map(Of Char, String) = Nothing, _
                               Optional ByVal useDefualtUnescapeMap As Boolean = True) As String
        Dim rtn As String = Nothing
        If unescapeEx(src, rtn, escapeChar, unescapeMap, useDefualtUnescapeMap) Then
            Return rtn
        Else
            Return Nothing
        End If
    End Function

    Public Function escapebackEx(ByVal src As String, Optional ByVal escapeChar As Char = character.rightSlash, _
                                 Optional ByVal unescapeMap As map(Of Char, String) = Nothing, _
                                 Optional ByVal useDefaultUnescapeMap As Boolean = True) As String
        Return unescapeEx(src, escapeChar, unescapeMap, useDefaultUnescapeMap)
    End Function

    Private Sub iem(ByVal c As Char, ByVal s As String)
        defaultEscapeMap(c) = s
    End Sub

    Private Sub iuem(ByVal c As Char, ByVal s As String)
        defaultUnescapeMap(c) = s
    End Sub

    Sub New()
        defaultEscapeMap = New map(Of Char, String)()
        defaultUnescapeMap = New map(Of Char, String)()
        iem(character.tab, character.t)
        iuem(character.t, character.tab)
        iem(character.return, character.r)
        iuem(character.r, character.return)
        iem(character.newline, character.n)
        iuem(character.n, character.newline)
        iem(character.vtab, character.v)
        iuem(character.v, character.vtab)
        iem(character.feed, character.f)
        iuem(character.f, character.feed)
        iem(character.backspace, character.b)
        iuem(character.b, character.backspace)
    End Sub

    Public Class unittests
        Public Shared Sub functional()
            Dim input As String = Nothing
            input = Console.ReadLine()
            While Not input Is Nothing
                raiseError("escape result " + escape(input))
                raiseError("unescape result " + unescape(input))
                raiseError("escapeEx result " + escapeEx(input))
                raiseError("unescapeEx result " + unescapeEx(input))

                input = Console.ReadLine()
            End While
        End Sub
    End Class
End Module
